unit uViewPCB ;

interface

uses
  Windows,
  Classes,
  Menus,
  Controls,
  Graphics,
  VirtualTrees,
  uLayout,
  uBasic,
  uPlacement,
  uMouseHandler,
  GDIPAPI,
  GDIPOBJ ;

type
  TMedaLayer = class( TMedaPlace )
  private
    fLayerType : TMedaLayerType ;
    fDroplayer : boolean ;
    function GetDroplayer : boolean ;
    procedure SetDropLayer( const Value : boolean ) ;
  protected
    procedure Update ; override ;
    function GetPopupMenu : TPopupMenu ; override ;
  public
    function GetName : string ; override ;
    function GetColor : TGPColor ; override ;
    function CheckType : TCheckType ; override ;
    procedure SetSelection( aFlag : TMedaState ) ; override ;
  public
    function Accept( Visitor : TObject ) : TObject ; override ;
    property LayerType : TMedaLayerType read fLayerType ;
    property DropLayer : boolean read GetDroplayer write SetDropLayer ;
    function InvalRect( aRect : TGPRectF ) : TGPRectF ; override ;
  end ;

  TMedaPCBViewer = class ;
  TMedaPCBInterface = class( TMedaViewable )
  private
    fParent : TMedaPCBViewer ;
    function GetSize : TGPSizeF ;
    function GetBase : single ;
  protected
    procedure Update ; override ;
    function GetPopupMenu : TPopupMenu ; override ;
  public
    constructor Create( aParent : TMedaPCBViewer ) ;
    function GetName : string ; override ;
    function GetChild( index : integer ) : TMedaViewable ; override ;
    function GetChildCount : integer ; override ;
    function GetIcon : TIconType ; override ;
    function GetColor : TGPColor ; override ;
    function GetText( aColumn : integer ) : string ; override ;
  public
    property Base : single read GetBase ;
    property Size : TGPSizeF read GetSize ;
    function Accept( Visitor : TObject ) : TObject ; override ;
    procedure Mark ; override ;
  end ;

  TMedaPCBViewer = class( TMedaViewer )
  private
    fProjectView : TMedaPCBInterface ;
    fMedaLayers : TMedaLayers ;
    fBase : single ;
    function GetLayer( iLayer : TMedaLayerType ) : TMedaLayer ;
    function GetAllLayers : TMedaLayers ;

    procedure SetVisibleLayerSet( const Value : TMedaLayerSet ) ;
    procedure SetWorkingLayerSet( const Value : TMedaLayerSet ) ;
    procedure SetDropLayerIndex( const Value : TMedaLayerType ) ;
    function GetDropLayerIndex : TMedaLayerType ;
    function GetVisibleLayerSet : TMedaLayerSet ;
    function GetWorkingLayerSet : TMedaLayerSet ;
    function GetDropLayer : TMedaLayer ;
  protected
    procedure CreateGraphics ; override ;
    function HitTest( aPoint : TGPPointF ) : TMedaViewList ; override ;
    procedure Paint ; override ;
  public
    constructor Create( AOwner : TComponent ) ; override ;
    destructor Destroy ; override ;
    procedure Mark ; virtual ;

    property ProjectView : TMedaPCBInterface read fProjectView ;
    procedure Clear ; override ;

    function CanZoomIn : boolean ; override ;
    function CanZoomOut : boolean ; override ;

    function LayerByID( aLayer : TGUID ) : TMedaLayer ;

    property Layers[ iLayer : TMedaLayerType ] : TMedaLayer read GetLayer ;
    property AllLayers : TMedaLayers read GetAllLayers ;

    property VisibleLayerSet : TMedaLayerSet read GetVisibleLayerSet write SetVisibleLayerSet ;
    property WorkingLayerSet : TMedaLayerSet read GetWorkingLayerSet write SetWorkingLayerSet ;
    property DropLayerIndex : TMedaLayerType read GetDropLayerIndex write SetDropLayerIndex ;
    property DropLayer : TMedaLayer read GetDropLayer ;
  end ;

var
  vsbPCBViewer      : TMedaPCBViewer ;

implementation

uses
  SysUtils,
  uVisitor,
  fmPCB ;

{ TMedaLayer }

function TMedaLayer.Accept( Visitor : TObject ) : TObject ;
begin
  Result := TMedaVisitor( Visitor ).VisitNode( Self ) ;
end ;

function TMedaLayer.GetColor : TGPColor ;
begin
  Result := GetPCBLayerColor( fLayerType ) ;
end ;

function TMedaLayer.GetName : string ;
begin
  Result := GetPCBLayerName( fLayerType ) ;
end ;

function TMedaLayer.GetPopupMenu : TPopupMenu ;
begin
  Result := TPopupMenu( Accept( PCBPopupVisitor as TPCBPopupVisitor ) ) ;
end ;

procedure TMedaLayer.SetSelection( aFlag : TMedaState ) ;
begin
  inherited ;
  TMedaPCBViewer( Parent ).Invalidate ;
  Invalidate ;
end ;

procedure TMedaLayer.Update ;
begin
  inherited ;
end ;

function TMedaLayer.CheckType : TCheckType ;
begin
  Result := ctTristateCheckbox ;
end ;

function TMedaLayer.InvalRect( aRect : TGPRectF ) : TGPRectF ;
begin
  Result := vsbPCBViewer.InvalRect( aRect ) ;
end ;

function TMedaLayer.GetDroplayer : boolean ;
begin
  Result := fDropLayer ;
end ;

procedure TMedaLayer.SetDropLayer( const Value : boolean ) ;
begin
  fDropLayer := Value ;
end ;

{ TMedaPCBInterface }

function TMedaPCBInterface.GetChildCount : integer ;
begin
  Result := ord( High( TMedaLayerType ) ) ; // one less
end ;

function TMedaPCBInterface.GetIcon : TIconType ;
begin
  Result := iconPCB ;
end ;

function TMedaPCBInterface.GetChild( index : integer ) : TMedaViewable ;
begin
  Result := TMedaLayer( fParent.Layers[ TMedaLayerType( index + 1 ) ] ) ; // one less, so shifted up
end ;

function TMedaPCBInterface.GetName : string ;
begin
  Result := 'PCB View' ;
end ;

function TMedaPCBInterface.GetPopupMenu: TPopupMenu;
begin
  Result := TPopupMenu( Accept( PCBPopupVisitor as TPCBPopupVisitor ) ) ;
end;

function TMedaPCBInterface.GetText( aColumn : integer ) : string ;
begin
  Result := '' ;
  case aColumn of
    0 : Result := GetName ;
  end ;
end ;

procedure TMedaPCBInterface.Mark ;
var
  i                 : TMedaLayerType ;
begin
  inherited ;
  for i := Low( TMedaLayerType ) to High( TMedaLayerType ) do
    if assigned( fParent.Layers[ i ] ) then
      fParent.Layers[ i ].Mark ;
end ;

procedure TMedaPCBInterface.Update ;
begin
end ;

function TMedaPCBInterface.GetColor : TGPColor ;
begin
  Result := aclMedaPCBView ;
end ;

constructor TMedaPCBInterface.Create( aParent : TMedaPCBViewer ) ;
begin
  inherited Create ;
  fParent := aParent ;
  Expanded := True ;
end ;

function TMedaPCBInterface.Accept( Visitor : TObject ) : TObject ;
begin
  Result := TMedaVisitor( Visitor ).VisitNode( Self ) ;
end ;

function TMedaPCBInterface.GetBase : single ;
begin
  with fParent do
    Result := fBase ;
end ;

function TMedaPCBInterface.GetSize : TGPSizeF ;
begin
  with fParent do
    Result := MakeSize( fCurrentWidth, fCurrentHeight ) ;
end ;

{ TMedaPCBViewer }

constructor TMedaPCBViewer.Create( AOwner : TComponent ) ;
begin
  inherited Create( AOwner ) ;
  fZoom := 0.5 ;
  fGrid := cPCBGrid ;
  fDensity := 2 ;
  fName := 'layer' ;
  fProjectView := TMedaPCBInterface.Create( Self ) ;

  fBackBrush := TGPSolidBrush.Create( aclBackPCB ) ;
  fGridPen0 := TGPPen.Create( aclGridPCB0 ) ;
  fGridPen1 := TGPPen.Create( aclGridPCB1 ) ;
  fGridPen2 := TGPPen.Create( aclGridPCB2 ) ;

  fMouseFactory := TMousePCBFactory.Create ;

  fBase := 25400 ;                      // 1 mil is 25400 nanometer
  fCurrentWidth := 10000 ;
  fCurrentHeight := 10000 ;

  Color := clTeal ;
  Clear ;
end ;

destructor TMedaPCBViewer.Destroy ;
var
  i                 : TMedaLayerType ;
begin
  for i := Low( TMedaLayerType ) to High( TMedaLayerType ) do
    fMedaLayers[ i ] := nil ;
  inherited ;
end ;

function TMedaPCBViewer.LayerByID( aLayer : TGUID ) : TMedaLayer ;
var
  i                 : TMedaLayerType ;
begin
  Result := nil ;
  for i := Low( TMedaLayerType ) to High( TMedaLayerType ) do
    if assigned( fMedaLayers[ i ] ) and
      IsEqualGUID( TMedaLayer( FMedaLayers[ i ] ).ID, aLayer ) then begin
      Result := TMedaLayer( fMedaLayers[ i ] ) ;
      Exit ;
    end ;
end ;

procedure TMedaPCBViewer.Mark ;
var
  i                 : TMedaLayerType ;
begin
  for i := Low( TMedaLayerType ) to High( TMedaLayerType ) do
    if assigned( fMedaLayers[ i ] ) then
      TMedaLayer( fMedaLayers[ i ] ).Mark ;
end ;

procedure TMedaPCBViewer.Clear ;
var
  i                 : TMedaLayerType ;
begin
  for i := Low( TMedaLayerType ) to High( TMedaLayerType ) do begin
    fMedaLayers[ i ] := TMedaLayer.Create ;
    TMedaLayer( fMedaLayers[ i ] ).Parent := Self ;
    TMedaLayer( fMedaLayers[ i ] ).fLayerType := i ;
    TMedaLayer( fMedaLayers[ i ] ).Name := GetPCBLayerName( i ) ;
  end ;
  VisibleLayerSet := [ lcComponent, lcSolder, lcMechanical ] ;
  WorkingLayerSet := [ lcComponent ] ;
  DropLayerIndex := lcComponent ;
  Invalidate ;
end ;

procedure TMedaPCBViewer.CreateGraphics ;
begin
  if not assigned( fGraphics ) then
    fGraphics := TMedaGraphics.Create( Canvas.Handle ) ;
  inherited ;
end ;

function TMedaPCBViewer.GetLayer( iLayer : TMedaLayerType ) : TMedaLayer ;
begin
  Result := TMedaLayer( fMedaLayers[ iLayer ] ) ;
end ;

function TMedaPCBViewer.GetAllLayers : TMedaLayers ;
begin
  Result := fMedaLayers ;
end ;

function TMedaPCBViewer.HitTest( aPoint : TGPPointF ) : TMedaViewList ;
var
  i                 : TMedaLayerType ;
begin
  CreateGraphics ;
  try
    Result := inherited HitTest( aPoint ) ;
    fGraphics.TranslateTransform( -fGraphics.Offset.X, -fGraphics.Offset.Y ) ;
    fGraphics.ScaleTransform( fZoom, fZoom ) ;
    for i := Low( TMedaLayerType ) to High( TMedaLayerType ) do
      if assigned( fMedaLayers[ i ] ) and fMedaLayers[ i ].Active then begin
        TMedaLayer( fMedaLayers[ i ] ).HitTest( aPoint, fGraphics, Result ) ;
        if assigned( Result ) then
          Exit ;
      end ;
  finally
    FreeGraphics ;
  end ;
end ;

procedure TMedaPCBViewer.Paint ;
var
  i                 : TMedaLayerType ;
begin
  CreateGraphics ;
  try
    inherited ;
    if assigned( fGraphics.MemGraphics ) then begin
      fGraphics.MemGraphics.TranslateTransform( -fGraphics.Offset.X, -fGraphics.Offset.Y ) ;
      fGraphics.MemGraphics.ScaleTransform( fZoom, fZoom ) ;
      for i := Low( TMedaLayerType ) to High( TMedaLayerType ) do
        if assigned( fMedaLayers[ i ] ) and ( Layers[ i ].GetSelection <> triFalse ) then
          TMedaLayer( fMedaLayers[ i ] ).PaintAt( fGraphics ) ;
      if assigned( Rats ) then
        Rats( fGraphics ) ;
      DrawBuffer ;
    end ;
  finally
    FreeGraphics ;
  end ;
end ;

function TMedaPCBViewer.CanZoomIn : boolean ;
begin
  Result := fZoom < 10 ;
end ;

function TMedaPCBViewer.CanZoomOut : boolean ;
begin
  Result := fZoom > 1 / 10 ;
end ;

procedure TMedaPCBViewer.SetVisibleLayerSet( const Value : TMedaLayerSet ) ;
var
  i                 : TMedaLayerType ;
begin
  for i := low( TMedaLayerType ) to High( TMedaLayerType ) do
    if assigned( Layers[ i ] ) then begin
      if i in Value then
        Layers[ i ].SetSelection( triMaybe )
      else
        Layers[ i ].SetSelection( triFalse ) ;
    end ;
end ;

procedure TMedaPCBViewer.SetWorkingLayerSet( const Value : TMedaLayerSet ) ;
var
  i                 : TMedaLayerType ;
begin
  for i := low( TMedaLayerType ) to High( TMedaLayerType ) do
    if assigned( Layers[ i ] ) then begin
      if i in Value then
        Layers[ i ].SetSelection( triTrue ) ;
    end ;
end ;

procedure TMedaPCBViewer.SetDropLayerIndex( const Value : TMedaLayerType ) ;
begin
  Layers[ lcComponent ].Droplayer := False ;
  Layers[ lcSolder ].Droplayer := False ;
  if Value in [ lcComponent, lcSolder ] then
    Layers[ Value ].Droplayer := True ;
end ;

function TMedaPCBViewer.GetDropLayer : TMedaLayer ;
begin
  Result := Layers[ lcComponent ] ;
  if Layers[ lcSolder ].Droplayer then
    Result := Layers[ lcSolder ] ;
end ;

function TMedaPCBViewer.GetDropLayerIndex : TMedaLayerType ;
begin
  Result := lcComponent ;
  if Layers[ lcSolder ].Droplayer then
    Result := lcSolder ;
end ;

function TMedaPCBViewer.GetVisibleLayerSet : TMedaLayerSet ;
var
  i                 : TMedaLayerType ;
begin
  Result := [ ] ;
  for i := low( TMedaLayerType ) to High( TMedaLayerType ) do
    if assigned( Layers[ i ] ) and ( Layers[ i ].GetSelection <> triFalse ) then
      Result := Result + [ i ] ;
end ;

function TMedaPCBViewer.GetWorkingLayerSet : TMedaLayerSet ;
var
  i                 : TMedaLayerType ;
begin
  Result := [ ] ;
  for i := low( TMedaLayerType ) to High( TMedaLayerType ) do
    if assigned( Layers[ i ] ) and Layers[ i ].Active then
      Result := Result + [ i ] ;
end ;

initialization
  vsbPCBViewer := TMedaPCBViewer.Create( nil ) ;

finalization
  vsbPCBViewer.Free ;

end.

